package com.example.rouroudate.ui.home.ui

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.View
import androidx.core.content.ContextCompat
import com.example.rouroudate.R
import com.example.rouroudate.ui.gallery.ui.StyleAnimationView
import com.example.rouroudate.util.DisplayUtils
import com.example.rouroudate.util.PrefManager
import com.example.rouroudate.util.TimeUtils
import kotlin.math.atan2
import kotlin.math.min

class CircleDateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    View(context, attrs, defStyleAttr) {

    companion object {
        const val TAG = "CircleDateView"

        private const val HURT = 0

        private const val CHILD = 2

        private const val SAFE = 1
    }

    private val strList = mutableListOf("零概率有饼饼期", "大概率有饼饼期", "极大概率有饼饼期", "极小概率有饼饼期")

    private var startAngle = 0f

    private var angle = 0f

    private lateinit var startDate: CircleDate

    private val today = CircleDate()

    private lateinit var currentDate: CircleDate

    private var circleRadius = 20f

    private var currentIndex = 0

    private lateinit var rect: RectF

    private val path = Path()

    private val pos = FloatArray(2)

    private val tan = FloatArray(2)

    private val pathMeasure = PathMeasure()

    private val safeColor = ContextCompat.getColor(context, R.color.safe_color)

    private val childColor = ContextCompat.getColor(context,R.color.child_color)

    private val hurtColor = ContextCompat.getColor(context,R.color.hurt_color)

    private var startDateTextY = 0f

    private var displayWidth = 0

    private var isCurrentMonth = false

    private var todayType = SAFE

    private var typeIdx = 0

    private var rectIdx = 0

    private var viewWidth = 0f

    private var preTextIndex = 0

    private var maxDateSize = PrefManager.getDateSetting().dateSize

    private val minDateSize = 15

    private var dateSize = 0

    private val centerPoint = PointF()

    private var styleType = PrefManager.getStyleType()

    private var isAlone = true

    fun setStartDate(circleDate: CircleDate) {
        startDate = circleDate
        postInvalidate()
    }

    private val paint = Paint().apply {
        color = Color.BLACK
        style = Paint.Style.FILL
        isAntiAlias = true
        textSize = circleRadius * 2
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        displayWidth = w
        initPath()
    }

    private fun initPath() {
        viewWidth = displayWidth / 1.2f
        startDateTextY = viewWidth / 2 + DisplayUtils.dp2px(30f)
        when (styleType) {
            StyleAnimationView.CircleType -> initStyleCircle()
            StyleAnimationView.HeartType -> initStyleHeart()
            else -> initStylePolygon()
        }
        centerPoint.set((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2)
        pathMeasure.setPath(path, false)
    }

    private fun initStyleCircle() {
        val l = (displayWidth - viewWidth) / 2
        val t = circleRadius * 5f
        rect = RectF(l, t, viewWidth + l, t + viewWidth)
        path.addArc(rect, 270f, 360f)
    }

    private fun initStyleHeart() {
        val radius = viewWidth / 2f
        val l = (displayWidth - viewWidth) / 2
        val t = circleRadius * 6f
        rect = RectF(l, t, viewWidth + l, t + viewWidth)
        path.moveTo(rect.left + radius, (rect.top + rect.bottom) * 0.17f)
        path.cubicTo(
            rect.right - radius * 0.3f, rect.top - radius * 0.7f,
            rect.right + radius * 0.8f, rect.top + radius * 0.9f,
            rect.left + radius, rect.bottom
        )
        path.cubicTo(
            rect.left - radius * 0.8f, rect.top + radius * 0.9f,
            rect.left + radius * 0.3f, rect.top - radius * 0.7f,
            rect.left + radius, (rect.top + rect.bottom) * 0.17f
        )
        path.close()
    }

    private fun initStylePolygon() {
        val l = (displayWidth - viewWidth) / 2
        val t = circleRadius * 5f
        rect = RectF(l, t, viewWidth + l, t + viewWidth)
        val outCirclePath = Path()
        val fivePathMeasure = PathMeasure()
        val angle = 5
        val posOut = FloatArray(2)
        var startAngle = 270f
        val sweepAngle = 360f / angle
        repeat(angle) {
            outCirclePath.reset()
            outCirclePath.addArc(rect, startAngle, sweepAngle)
            fivePathMeasure.setPath(outCirclePath, false)
            fivePathMeasure.getPosTan(0f, posOut, null)
            when (it) {
                0 -> path.moveTo(posOut[0], posOut[1])
                else -> path.lineTo(posOut[0], posOut[1])
            }
            startAngle += sweepAngle
        }
        path.close()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.let {
            drawView(it)
        }
    }

    private fun drawView(it: Canvas) {
        styleType = PrefManager.getStyleType()

        currentIndex = 0
        preTextIndex = -1
        currentDate = startDate.deepCopy()
        isCurrentMonth = startDate.isCurrentDate()

        isAlone = true
        todayType = SAFE
        typeIdx = currentDate.settingData.dateSize
        rectIdx = 0

        if (!isCurrentMonth) {
            maxDateSize = min(currentDate.settingData.dateSize, 40)
        }

        dateSize = min(currentDate.settingData.dateSize, maxDateSize)
        angle = 360f / dateSize

        startAngle = 270f - angle / 2

        if (dateSize > currentDate.settingData.hurtSize) {
            drawHurtDate(currentDate.settingData.hurtSize, it)
        } else {
            drawHurtDate(dateSize, it)
        }
        val safeCount = if (dateSize > currentIndex) 1 else 0
        when {
            (dateSize - 19 >= currentIndex) -> {
                drawSafeDate(dateSize - 19 - currentIndex + safeCount, it)
                drawChildDate(it, 10)
                drawSafeDate(dateSize - currentIndex, it)
            }
            (dateSize - 14 >= currentIndex) -> {
                drawSafeDate(safeCount, it)
                drawChildDate(it, dateSize - 14 - currentIndex + 5)
                drawSafeDate(dateSize - currentIndex, it)
            }
            else -> {
                drawSafeDate(safeCount, it)
                drawChildDate(it, dateSize - 9 - currentIndex)
                drawSafeDate(dateSize - currentIndex, it)
            }
        }

        drawTips(it)
    }

    private fun drawHurtDate(size: Int, canvas: Canvas) {
        paint.color = hurtColor
        drawDate(size, canvas, HURT)
    }

    private fun drawSafeDate(size: Int, canvas: Canvas) {
        paint.color = safeColor
        drawDate(size, canvas, SAFE)
    }

    private fun drawChildDate(canvas: Canvas, size: Int) {
        paint.color = childColor
        drawDate(size, canvas, CHILD)
    }

    private fun setPaintColor(type: Int) {
        paint.color = when (type) {
            HURT -> hurtColor
            SAFE -> safeColor
            CHILD -> childColor
            else -> Color.WHITE
        }
    }

    private fun drawDate(size: Int, canvas: Canvas, type: Int) {
        if (size < 0) return
        setPaintColor(type)
        for (i in 0 until size) {
            val len = pathMeasure.length / dateSize * currentIndex
            pathMeasure.getPosTan(len, pos, tan)
            canvas.drawCircle(pos[0], pos[1], circleRadius, paint)
            if (i == 0 || (i == size - 1 && size > 1)) {
                drawCircleText(canvas)
            }
            if (type == CHILD) {
                if (size > 4 && i == size - 5) {
                    rectIdx = i + 1
                    drawRectInCircle(canvas)
                    drawCircleText(canvas)
                }
            }
            if (currentDate.isSameDate(today)) {
                drawToday(canvas, i, type)
            }
            currentDate.addDay(1)
            currentIndex += 1
            startAngle += angle
        }
    }

    //unite rect
    private fun drawRectInCircle(canvas: Canvas) {
        rectIdx
        paint.color = Color.WHITE
        val w = circleRadius / 2f
        val h = circleRadius / 2f
        val l = pos[0] - w / 2
        val t = pos[1] - h / 2
        canvas.drawRect(l, t, l + w, t + h, paint)
        paint.color = childColor
    }

    //时间指示
    private fun drawCircleText(canvas: Canvas) {
        if (preTextIndex == currentIndex) return
        val dstPath = Path()
        val len = circleRadius * 2.5f
        val degrees = if (currentIndex == 0) {
            0f
        } else {
            (atan2(tan[1], tan[0]) * 180.0 / Math.PI).toFloat()
        }
        if ((degrees in 90.0..180.0) || (degrees >= -180 && degrees <= -90)) {
            canvas.rotate(degrees - 180, pos[0], pos[1])
        } else {
            canvas.rotate(degrees, pos[0], pos[1])
        }
        val textRect = RectF(pos[0] - len, pos[1] - len, pos[0] + len, pos[1] + len)

        val textColor = paint.color
        paint.textSize = circleRadius * 1.2f
        paint.isFakeBoldText = true
        paint.color = Color.BLACK

        val str = currentDate.getMonthDay()
        val tw = paint.measureText(str)
        val hOffset = (len * 2 - tw) / 2f
        val vOffset= 0f
        Log.d(TAG, "currentDate = $str degrees = $degrees height = ${textRect.height()}")
        if (preTextIndex + 1 == currentIndex) {
            if (isAlone) {
                dstPath.moveTo(textRect.left, textRect.top)
                dstPath.lineTo(textRect.right, textRect.top)
                canvas.drawTextOnPath(str, dstPath, hOffset, vOffset, paint)
            } else {
                dstPath.moveTo(textRect.left, textRect.bottom)
                dstPath.lineTo(textRect.right, textRect.bottom)
                canvas.drawTextOnPath(str, dstPath, hOffset, vOffset, paint)
            }
            isAlone = !isAlone
        } else {
            isAlone = true
            dstPath.moveTo(textRect.left, textRect.bottom)
            dstPath.lineTo(textRect.right, textRect.bottom)
            canvas.drawTextOnPath(str, dstPath, hOffset, vOffset, paint)
        }
        if ((degrees in 90.0..180.0) || (degrees >= -180 && degrees <= -90)) {
            canvas.rotate(180 - degrees, pos[0], pos[1])
        } else {
            canvas.rotate(-degrees, pos[0], pos[1])
        }
        paint.color = textColor
        preTextIndex = currentIndex
    }

    //绘制当日半透明光圈
    private fun drawToday(canvas: Canvas, idx: Int, type: Int) {
        todayType = type
        typeIdx = idx + 1
        val alpha = paint.alpha
        paint.alpha = 120
        canvas.drawCircle(pos[0], pos[1], circleRadius * 2, paint)
        paint.alpha = alpha
    }

    //绘制文字提示
    private fun drawTips(canvas: Canvas) {
        paint.textSize = circleRadius * 2
        paint.isFakeBoldText = true
        pos[0] = (displayWidth - circleRadius * 2 * 4 - paint.measureText(strList[0]) * 2) / 2
        pos[1] = rect.bottom + DisplayUtils.dp2px(40f)

        var fontMetrics = paint.fontMetrics
        val textY = pos[1] + circleRadius - fontMetrics.bottom / 2

        //零概率有饼饼期
        paint.color = hurtColor
        canvas.drawCircle(pos[0], pos[1], circleRadius, paint)

        //大概率有饼饼期
        paint.color = childColor
        canvas.drawCircle(pos[0], pos[1] + circleRadius * 3, circleRadius, paint)

        //零概率有饼饼期
        paint.color = Color.BLACK
        pos[0] += circleRadius * 2
        canvas.drawText(strList[0], pos[0], textY, paint)

        //大概率有饼饼期
        canvas.drawText(strList[1], pos[0], textY + circleRadius * 3, paint)

        //极大概率有饼饼期
        pos[0] += circleRadius * 2 + paint.measureText(strList[0])
        paint.color = childColor
        canvas.drawCircle(pos[0], pos[1], circleRadius, paint)
        drawRectInCircle(canvas)

        //极小概率有饼饼期
        paint.color = safeColor
        canvas.drawCircle(pos[0], pos[1] + circleRadius * 3, circleRadius, paint)

        //极大概率有饼饼期
        paint.color = Color.BLACK
        pos[0] += circleRadius * 2
        canvas.drawText(strList[2], pos[0], textY, paint)

        //极小概率有饼饼期
        canvas.drawText(strList[3], pos[0], textY + circleRadius * 3, paint)

        //日期时间
        if (!isCurrentMonth) {
            val hLen = DisplayUtils.dp2px(20f)
            paint.textSize = circleRadius * 5
            var str = String.format("%s年", startDate.year)
            var tw = paint.measureText(str)
            fontMetrics = paint.fontMetrics
            val th = fontMetrics.bottom - fontMetrics.top
            pos[0] = centerPoint.x - tw / 2
            pos[1] = startDateTextY + hLen
            canvas.drawText(str, pos[0], pos[1], paint)
            paint.textSize = circleRadius * 2
            str = String.format("周期%s天，${strList[0]}%s天", startDate.settingData.dateSize, currentDate.settingData.hurtSize)
            tw =  paint.measureText(str)
            pos[0] = centerPoint.x - tw / 2
            pos[1] += th / 2
            canvas.drawText(str, pos[0], pos[1], paint)

            if (startDate.settingData.dateSize > maxDateSize || startDate.settingData.dateSize < minDateSize) {
                str = if (startDate.settingData.dateSize > maxDateSize) {
                    context.getString(R.string.date_too_long)
                } else {
                    context.getString(R.string.date_too_short)
                }
                tw =  paint.measureText(str)
                pos[0] = centerPoint.x - tw / 2
                pos[1] += th / 2
                canvas.drawText(str, pos[0], pos[1], paint)

                if (startDate.settingData.dateSize > maxDateSize) {
                    str = context.getString(R.string.max_date)
                    tw =  paint.measureText(str)
                    pos[0] = centerPoint.x - tw / 2
                    pos[1] += th / 2
                    canvas.drawText(str, pos[0], pos[1], paint)
                }
            }
        } else {
            var str = when(todayType) {
                HURT -> strList[0]
                SAFE -> strList[3]
                else -> {
                    if (rectIdx == typeIdx) {
                        strList[2]
                    } else {
                        strList[1]
                    }
                }
            }
            var tw = paint.measureText(str)
            fontMetrics = paint.fontMetrics
            var th = fontMetrics.bottom - fontMetrics.top
            setPaintColor(todayType)
            pos[0] = centerPoint.x
            pos[1] = startDateTextY - DisplayUtils.dp2px(30f)
            val l = pos[0] - tw / 1.8f
            val t = pos[1] - th
            val base = pos[1] - fontMetrics.bottom
            val b = t + (base - t) * 2
            canvas.drawRoundRect(l, t, l + tw / 0.9f, b, circleRadius, circleRadius, paint)
            paint.color = Color.BLACK
            pos[0] = centerPoint.x - tw / 2
            canvas.drawText(str, pos[0], pos[1], paint)
            paint.textSize = circleRadius * 4
            str = String.format("第%s天", typeIdx)
            tw = paint.measureText(str)
            fontMetrics = paint.fontMetrics
            th = fontMetrics.bottom - fontMetrics.top
            pos[1] = b + 20 + th
            pos[0] = centerPoint.x - tw / 2
            canvas.drawText(str, pos[0], pos[1], paint)

            if (startDate.settingData.dateSize > maxDateSize) {
                val today = CircleDate()
                paint.textSize = circleRadius * 2
                str = String.format("无饼饼期已经迟到%s天了", TimeUtils.getDateSize(today, startDate) - maxDateSize)
                tw =  paint.measureText(str)
                pos[0] = centerPoint.x - tw / 2
                pos[1] += th / 2
                canvas.drawText(str, pos[0], pos[1], paint)
            }
        }
    }
}